// EasyAspect.java
package com.easy.aspect;

import com.easy.annotation.LogMethod;
import com.easy.bean.Admin;
import com.easy.bean.AdminLog;
import com.easy.mapper.AdminDao;
import com.easy.service.AdminLogService;
import com.easy.util.TokenUtil;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Arrays;

@Component
@Aspect
public class EasyAspect {

    @Autowired
    private AdminLogService adminLogService;

    @Autowired
    private AdminDao adminDao;

    @Around(value = "@annotation(logMethod)")
    public Object recordLog(ProceedingJoinPoint point, LogMethod logMethod) throws Throwable {
        Object obj = null;
        StringBuilder strb = new StringBuilder();
        String serviceName = logMethod.serviceName();
        boolean recordParam = logMethod.recordParam();
        boolean recordReturn = logMethod.recordReturn();

        // 获取方法签名
        MethodSignature methodSignature = (MethodSignature) point.getSignature();
        String methodName = methodSignature.getMethod().getName();
        String className = point.getTarget().getClass().getSimpleName();

        strb.append("[");
        strb.append(serviceName);
        strb.append("]");
        strb.append("  method:");
        strb.append(className).append(".").append(methodName);

        if (recordParam) {
            strb.append("  param:");
            Object[] args = point.getArgs();
            if (args != null && args.length > 0) {
                strb.append(Arrays.toString(args));
            }
        }

        long startTime = System.currentTimeMillis();
        try {
            obj = point.proceed();
        } catch (Exception e) {
            strb.append("  exception:");
            strb.append(e.getMessage());
            throw e;
        } finally {
            long endTime = System.currentTimeMillis();

            if (recordReturn && obj != null) {
                strb.append("  return:");
                strb.append(obj.toString());
            }

            // 添加执行时间
            strb.append("  executionTime:");
            strb.append(endTime - startTime);
            strb.append("ms");

            Date date = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
            strb.append("     [");
            strb.append(sdf.format(date));
            strb.append("]");

            // 输出到控制台
            System.out.println(strb.toString());

            // 保存到数据库
            saveLogToDatabase(serviceName, strb.toString(), date, className, methodName, point.getArgs());
        }

        return obj;
    }

    private void saveLogToDatabase(String actionType, String actionDetails, Date actionTime,
                                   String className, String methodName, Object[] args) {
        try {
            AdminLog adminLog = new AdminLog();
            adminLog.setActionType(actionType);
            adminLog.setActionDetails(actionDetails);
            adminLog.setActionTime(actionTime);
            adminLog.setDeletedAt(0);
            adminLog.setTargetTable(extractTargetTable(className, methodName));

            // 从token中获取用户信息
            String adminId = getAdminIdFromToken();
            adminLog.setAdminId(adminId != null ? adminId : "unknown");

            // 获取IP地址
            String ipAddress = getClientIpAddress();
            adminLog.setIpAddress(ipAddress);

            // 设置目标ID
            String targetId = extractTargetId(args);
            adminLog.setTargetId(targetId != null ? targetId : "");

            // 异步保存日志，避免影响主业务流程
            new Thread(() -> {
                try {
                    adminLogService.saveLog(adminLog);
                } catch (Exception e) {
                    System.err.println("保存操作日志失败: " + e.getMessage());
                    e.printStackTrace();
                }
            }).start();
        } catch (Exception e) {
            System.err.println("记录操作日志异常: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 从token中获取管理员ID
     * @return 管理员ID
     */
    private String getAdminIdFromToken() {
        try {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes != null) {
               HttpServletRequest request = attributes.getRequest();

                if (request != null) {
                    // 获取token
                    String token = getTokenFromRequest(request);

                    if (token != null && !token.isEmpty() && TokenUtil.verify(token)) {
                        // 从token中获取member信息
                        Object memberObj = TokenUtil.getOption(token, "member");

                        if (memberObj != null) {
                            String member = memberObj.toString();
                            if (!member.isEmpty()) {
                                // 根据member查询admin信息
                                Admin admin = adminDao.getByMember(member);

                                if (admin != null && admin.getId() != null) {
                                    return String.valueOf(admin.getId());
                                }
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            System.err.println("解析token失败: " + e.getMessage());
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 从请求中获取token（用HttpServletRequest替代反射）
     * @param request HttpServletRequest对象（不再是Object）
     * @return token字符串
     */
// 注意：参数类型从 Object 改为 HttpServletRequest，更明确
    private String getTokenFromRequest(HttpServletRequest request) {
        try {
            // 1. 优先从 Header 中获取 Token（符合行业规范，前端通常放 Header）
            String token = request.getHeader("token");


            // 2. 若 Header 没有，从 URL 参数中获取（兼容特殊场景，如文件下载链接）
            if (token == null || token.trim().isEmpty()) {
                token = request.getParameter("token");

            }

            // 3. 额外兼容：若前端用 Authorization 头（带 Bearer 前缀，如 OAuth2 格式）
            if (token == null || token.trim().isEmpty()) {
                token = request.getHeader("Authorization");
                if (token != null && token.startsWith("Bearer ")) {
                    token = token.substring(7); // 去除 "Bearer " 前缀（如 "Bearer xxx" → "xxx"）
                    System.out.println("从 Header[Authorization] 提取并处理后的 Token：" + token);
                }
            }

            return token;
        } catch (Exception e) {
            System.err.println("获取 Token 失败：" + e.getMessage());
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获取客户端IP地址
     * @return IP地址
     */
    private String getClientIpAddress() {
        try {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes != null) {
                Object request = attributes.getRequest();
                if (request != null) {
                    String ipAddress = null;

                    try {
                        ipAddress = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, "X-Forwarded-For");
                    } catch (Exception e) {
                        // 忽略异常
                    }

                    if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
                        try {
                            ipAddress = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, "Proxy-Client-IP");
                        } catch (Exception e) {
                            // 忽略异常
                        }
                    }

                    if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
                        try {
                            ipAddress = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, "WL-Proxy-Client-IP");
                        } catch (Exception e) {
                            // 忽略异常
                        }
                    }

                    if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
                        try {
                            ipAddress = (String) request.getClass().getMethod("getRemoteAddr").invoke(request);
                        } catch (Exception e) {
                            // 忽略异常
                        }
                    }

                    return ipAddress;
                }
            }
        } catch (Exception e) {
            System.err.println("获取IP地址失败: " + e.getMessage());
        }
        return "unknown";
    }

    /**
     * 根据类名和方法名提取目标表名
     * @param className 类名
     * @param methodName 方法名
     * @return 目标表名
     */
    private String extractTargetTable(String className, String methodName) {
        // 根据类名推断操作的表名
        if (className.contains("Category")) {
            return "category";
        } else if (className.contains("Product")) {
            return "product";
        } else if (className.contains("Brand")) {
            return "brand";
        } else if (className.contains("Pattern")) {
            return "pattern";
        } else if (className.contains("Sizes")) {
            return "sizes";
        } else if (className.contains("Product_Size")) {
            return "product_size";
        } else if (className.contains("Top_Pattern")) {
            return "top_pattern";
        }
        return className.toLowerCase();
    }

    /**
     * 从方法参数中提取目标ID
     * @param args 方法参数
     * @return 目标ID
     */
    private String extractTargetId(Object[] args) {
        if (args != null) {
            for (Object arg : args) {
                if (arg instanceof Integer) {
                    return String.valueOf(arg);
                } else if (arg != null) {
                    // 尝试从对象中获取ID属性
                    try {
                        java.lang.reflect.Method[] methods = arg.getClass().getMethods();
                        for (java.lang.reflect.Method method : methods) {
                            if (method.getName().equals("getId") && method.getParameterCount() == 0) {
                                Object result = method.invoke(arg);
                                if (result instanceof Integer || result instanceof Long) {
                                    return String.valueOf(result);
                                }
                            }
                        }
                    } catch (Exception e) {
                        // 忽略异常
                    }
                }
            }
        }
        return null;
    }
}
